package logic;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.DatagramPacket;
import java.util.Random;
import java.util.Vector;


public class ThreadRemoved implements Runnable{
	public static int backupRepeats = 5;
	public static int delay = 400;
	public static int delayBackup = 500;
	private Server server;
	private DatagramPacket receivePacket;
	private final String defautVersion="1.0";
	public ThreadRemoved(Server server,DatagramPacket receivePacket)
	{
		this.setServer(server);
		this.receivePacket=receivePacket;
	}
	public void run(){
		String message_received = new String( receivePacket.getData(),0,receivePacket.getLength());
		String[] chunkParts=new String[10];
		int indexFinalHeader = message_received.indexOf("\r\n\r\n");
		if(indexFinalHeader == -1)
		{
			System.out.println(message_received);
			System.out.println(receivePacket.getAddress().toString());
		}
		else if(indexFinalHeader != -1)
		{
			String header = message_received.substring(0, indexFinalHeader);
			chunkParts=header.split(" ");

			long initTime = System.currentTimeMillis();
			String fileID = chunkParts[2];
			int chunkNo = Integer.parseInt(chunkParts[3]);
			Chunk chunk = new Chunk(fileID , chunkNo);
			myFile file = new myFile(fileID);
			try {
				if(Server.getChunkRepository().getChunks().contains(chunk))//verificar se tambem possui o mesmo chunk para actualizar o grau de replicac��o
				{

					int indexChunk = Server.getChunkRepository().getChunks().indexOf(chunk);
					Chunk  chunkTmp = Server.getChunkRepository().getChunks().elementAt(indexChunk);
					chunkTmp.removeIP(receivePacket.getAddress().toString());

					if(chunkTmp.getReplicationDeg()>chunkTmp.getIps().size())
					{
						backup_subprotocol(fileID, chunkNo, initTime, chunkTmp.getReplicationDeg());//executa o subprotocolo de backup
					}

					Server.getChunkRepository().saveInFile(Server.CHUNKS);
				}
				else if(Server.getFileRepository().getFiles().contains(file)){//verificar se o chunk faz parte de um dos seus ficheiros enviados e actualiza o grau de replicacao

					int indexFile = Server.getFileRepository().getFiles().indexOf(file);
					myFile fileTmp = Server.getFileRepository().getFiles().elementAt(indexFile);
					fileTmp.removeIP(receivePacket.getAddress().toString(), chunkNo);

					if(fileTmp.getIps().elementAt(chunkNo).size()<fileTmp.getReplicationDeg())
					{
						backup_subprotocol(fileID, chunkNo, initTime,fileTmp.getReplicationDeg());//executa o subprotocolo de backup
					}

					Server.getFileRepository().saveInFile(server.FILES);

				}
			} catch (IOException | InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public Server getServer() {
		return server;
	}
	public void setServer(Server server) {
		this.server = server;
	}
	public void backup_subprotocol(String fileID,int chunkNo, long initTime, int repDeg) throws IOException, InterruptedException
	{
		PutchunkMessage p = new PutchunkMessage(fileID, chunkNo);
		boolean contains=false;
		byte[] sendData = new byte[65000];

		byte[] content = new byte[64000];
		InputStream is = null;


		int n=0;

		try{
			is = new FileInputStream(fileID+chunkNo);
			n=is.read(content);
			is.close();
		}catch(Exception  e)
		{
			//e.printStackTrace();
			return;

		}

		String reply = new String("PUTCHUNK "+defautVersion+" "+fileID+" "+chunkNo+" "+repDeg+" "+Server.CR+Server.LF+Server.CR+Server.LF+content);
		sendData=reply.getBytes();
		byte[] sendData2 = new byte[sendData.length+n];

		for(int j=0;j<sendData.length;j++)
		{

			sendData2[j]=new Byte(sendData[j]);

		}
		for(int j=0;j<n;j++)
		{

			sendData2[sendData.length+j]=new Byte(content[j]);

		}
		DatagramPacket sendPacket = new DatagramPacket(sendData2, sendData2.length, server.getMDB_address(), server.getMDB_port());

		Random randomGenerator = new Random();
		long random = randomGenerator.nextInt(Server.delay);
		Thread.sleep(random);
		if(server.getPutchunkMessages().contains(p))//verifica se ja foi enviado o put chunk
		{
			int index=server.getPutchunkMessages().indexOf(p);
			if(server.getPutchunkMessages().get(index).getDate()>=initTime)
				contains=true;
		}
		long delayTemp =delayBackup;
		Chunk ch=new Chunk(fileID,chunkNo);
		int index=Server.getChunkRepository().getChunks().indexOf(ch);
		if(index!=-1)
		{
			Vector<String> ips=Server.getChunkRepository().getChunks().get(index).getIps();
			if(!contains && !Server.enhancement )
			{

				//ips.clear();


				for(int i =0 ; i < backupRepeats; i++)
				{
					server.getMDB_socket().send(sendPacket);
					Thread.sleep(delayTemp);
					for(int j=0;j<server.getStoredMessages().size();j++)
					{
						if(server.getStoredMessages().get(j).getChunkNo()== chunkNo 
								&& server.getStoredMessages().get(j).getFileID().equals(fileID))
						{
							if(!ips.contains(server.getStoredMessages().get(j).getIp()))
							{
								ips.add(server.getStoredMessages().get(j).getIp());
								server.getStoredMessages().remove(j);
								j--;

							}
						}

					}
					if(ips.size()>=Server.getChunkRepository().getChunks().get(index).getReplicationDeg())
						break;

					delayTemp +=delayBackup;

				}
			}
			else if(Server.enhancement )
			{


				for(int i =0 ; i < backupRepeats; i++)
				{
					if(!contains)
					{
						server.getMDB_socket().send(sendPacket);
					}
					Thread.sleep(delayTemp);
					for(int j=0;j<server.getStoredMessages().size();j++)
					{
						if(server.getStoredMessages().get(j).getChunkNo()== chunkNo 
								&& server.getStoredMessages().get(j).getFileID().equals(fileID))
						{
							if(!ips.contains(server.getStoredMessages().get(j).getIp()))
							{
								ips.add(server.getStoredMessages().get(j).getIp());
								server.getStoredMessages().remove(j);
								j--;

							}
						}

					}

					if(ips.size()>=Server.getChunkRepository().getChunks().get(index).getReplicationDeg())
						break;

					if(contains)	
					{
						random = randomGenerator.nextInt(Server.delay);
						Thread.sleep(random);
						if(server.getPutchunkMessages().contains(p))//verifica se ja foi enviado o put chunk
						{
							int index2=server.getPutchunkMessages().indexOf(p);
							if(server.getPutchunkMessages().get(index2).getDate()>=initTime)
								contains=true;
						}
					}
					delayTemp +=delayBackup;


				}

			}
		}
	}

	public String getDefautVersion() {
		return defautVersion;
	}
}
